#include <stdio.h>
#include <string.h>

#include "fatfs.h"

#include "menu.h"

#include "audio.h"
#include "ape.h"

// #include "arm_math.h"

//////////////////////////////////////////////////////////////////////////////////
//本程序移植自RockBox的ape解码库
//ALIENTEK STM32F407开发板
//APE 解码代码
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//创建日期:2014/6/29
//版本：V1.0
//********************************************************************************
//V1.0 说明
//1,支持16位单声道/立体声ape的解码
//2,最高支持96K的APE格式(LV1流畅,LV2小卡)
//3,LV1~LV3,在48K及以下流畅播放,LV4,LV5大卡.
//4,对某些ape文件,可能不支持,请用Monkey's Audio软件进行转换一下,即可正常播放
//////////////////////////////////////////////////////////////////////////////////

int currentframe;
int nblocks;

struct ape_ctx_t apex;

uint32_t fsize;

uint8_t *readptr;
uint8_t *buffer;

int *decoded0;
int *decoded1;

uint32_t totalsamples;

int bytesconsumed;
int bytesinbuffer;
int blockstodecode;
int firstbyte;
int n;

uint8_t new_frame;

// apedecoder.c里面需要的数组
// char filterbuf[2816];

uint32_t *ape_seektable;

extern filter_int *filterbuf64;		// 需要2816字节

extern int disp;

volatile unsigned char apetransferend = 0;	// i2s传输完成标志
volatile unsigned char apewitchbuf = 0;		// i2sbufx指示标志

static void ape_fill_buffer(uint16_t *buf, uint16_t size);
static void set_volume(int bps, int size, int16_t *data);

/**
  * @brief  The application .
  * @retval void
  */
void process_ape_buffer(void)
{
	Is_Process_buffer = 0;

	pAudio->exchange 	= pAudio->play_buff;
	pAudio->play_buff 	= pAudio->read_buff;
	pAudio->read_buff 	= pAudio->exchange;

	// frame 循环
	if(currentframe < apex.totalframes) {	// 还有未解码的帧?
		if(new_frame) {
			// 计算一帧里面有多少个blocks?
			if(currentframe == (apex.totalframes - 1)) {
				nblocks = apex.finalframeblocks;
			} else  {
				nblocks = apex.blocksperframe;
			}
			apex.currentframeblocks = nblocks;

			// 初始化帧解码
			init_frame_decoder(&apex, readptr, &firstbyte, &bytesconsumed);

			readptr += bytesconsumed;

			bytesinbuffer -= bytesconsumed;

			new_frame = 0;
		}

		// block 循环
		// 获得一次要解码的blocks个数
		blockstodecode = AUDIO_MIN(APE_BLOCKS_PER_LOOP, nblocks);

		// printf("block decode ->\r\n");
		retSD = decode_chunk(&apex, readptr, &firstbyte, &bytesconsumed, decoded0, decoded1, blockstodecode);
		if(retSD != 0) {
			printf("block decode err\r\n");
			Play_Next();
			return ;
		} else {
			printf("\rape_decode_chunk  block : %d frame : %d bytesconsumed : %d", nblocks, currentframe, bytesconsumed);
		}

		ape_fill_buffer((uint16_t *)decoded1, blockstodecode * 2);

		pAudio->bytesRead = blockstodecode * 4;
		// play_size = (uint32_t)(bytesRead / 1);

		readptr += bytesconsumed;			// 解码指针偏移到新数据位置
		bytesinbuffer -= bytesconsumed; 	// buffer里面的数据量减少

		//	出现错误了
		if(bytesconsumed > 4 * APE_BLOCKS_PER_LOOP) {
			nblocks = 0;
			printf("bytesconsumed:%d\r\n", bytesconsumed);
			Play_Next();
			return ;
		}

		// 需要补充新数据了
		if(bytesinbuffer < 4 * APE_BLOCKS_PER_LOOP) {
			memmove(buffer, readptr, bytesinbuffer);
			// Is_Busy = 1;
			retSD = f_read(&SDFile, buffer + bytesinbuffer, APE_FILE_BUF_SZ - bytesinbuffer, (uint32_t *)&n);
			if(retSD) {
				printf("file read error !\r\n");
				Play_Next();
				return ;
			}
			// Is_Busy = 0;
			bytesinbuffer += n;
			readptr = buffer;
		}

		// block计数递减
		nblocks -= blockstodecode;
		// printf("ape_decode_chunk  block : %d frame : %d bytesconsumed : %d \r\n", nblocks, currentframe, bytesconsumed);

		if(nblocks < APE_BLOCKS_PER_LOOP) {
			currentframe++;
			new_frame = 1;
		}
	} else {

		audio_Stop();

		printf("\r\nplay finished  %02d:%02d\r\n", min, sec);

		Play_Next();
	}
}

//填充PCM数据到DAC
//buf:PCM数据首地址
//size:pcm数据量(16位为单位)
static void ape_fill_buffer(uint16_t *buf, uint16_t size)
{
	uint16_t i;
	uint16_t *p;

	apetransferend = 0;

	p = (uint16_t *)pAudio->read_buff;

	for(i = 0; i < size; i++)  p[i] = buf[i];

	// fill zero
	if(size < APE_BLOCKS_PER_LOOP * 2) {
		for(; i < APE_BLOCKS_PER_LOOP * 2; i++)  p[i] = 0x0000;
	}

	// if(volume)	set_volume(16, size, (int16_t *)pAudio->read_buff);

}

/**
  * @brief  The application .
  * @retval void
  */
static void set_volume(int bps, int size, int16_t *data)
{
	// 调整音量临时指针
	uint16_t  num_vol;
	int16_t   *temp_vol;
	// int32_t   *temp_vol_24;
	int32_t   vol;

	temp_vol = data;

	if(bps == 16) {

		for(num_vol = 0; num_vol < size; num_vol++)
			*temp_vol++ >>= volume;

	} else if(bps == 24) {

		for(num_vol = 0; num_vol < size; num_vol++) {
			vol = temp_vol[num_vol * 2 + 1] | ((temp_vol[num_vol * 2]) << 16);

			vol >>= volume;

			temp_vol[num_vol * 2 + 1] = (int16_t)(vol & 0xffff);
			temp_vol[num_vol * 2] = (int16_t)((vol >> 16) & 0xffff);
			// *temp_vol_24++ >>= (volume-1);
		}
	}
}

//播放一曲FLAC音乐
//fname:FLAC文件路径.
//返回值:0,正常播放完成
//[b7]:0,正常状态;1,错误状态
//[b6:0]:b7=0时,表示操作码
//       b7=1时,表示有错误(这里不判定具体错误,0X80~0XFF,都算是错误)
int Ape_Play(char *fname)
{
	char header[64];

	int totalsec;

	Is_finished = 0;
	Is_End_chunk = 0;

	currentframe = 0;

	memset(pAudio, 0x00, sizeof(AUDIO_DEV));

	filterbuf64 = (filter_int *)buffPointer;	// filterbuf64 need  2816 bytes

	decoded0 = (int *)&buffPointer[3096];
	decoded1 = (int *)&buffPointer[3096 + APE_BLOCKS_PER_LOOP * 4];

	pAudio->buff_A = (uint16_t *)&buffPointer[3096 + APE_BLOCKS_PER_LOOP * 8];
	pAudio->buff_B = (uint16_t *)&buffPointer[3096 + APE_BLOCKS_PER_LOOP * 12];

	buffer = (uint8_t *)&buffPointer[3096 + APE_BLOCKS_PER_LOOP * 16]; // mymalloc(SRAMIN, APE_FILE_BUF_SZ);

	ape_seektable = (uint32_t *)&buffPointer[3096 + APE_BLOCKS_PER_LOOP * 16 + APE_FILE_BUF_SZ];
	apex.seektable = ape_seektable;

	retSD = f_open(&SDFile, (char *)fname, FA_READ);		//打开文件
	if(retSD != FR_OK) {
		printf("Could not open: %s\r\n", fname);
		return -1;
	} else {
		printf("\r\n>>>Open: %s OK\r\n", fname);
	}

	fsize = f_size(&SDFile);

	retSD = ape_parseheader(&SDFile, &apex); // 分析ape文件头
	if(retSD != 0) {
		printf("ape_parseheader failed !\r\n");
		return -2;
	}

	if((apex.compressiontype > 3000)        ||
	   (apex.fileversion < APE_MIN_VERSION) ||
	   (apex.fileversion > APE_MAX_VERSION  ||
	    apex.bps != 16)) {
		//压缩率不支持  版本不支持  不是16位音频格式
		printf("ape format not supported !\r\n");
		return -1;
	}

	// apectrl.bps = apex.bps;					// 得到采样深度(ape,我们仅支持16位)
	// apectrl.samplerate = apex.samplerate;	// 得到采样率,ape支持48Khz以下的采样率,在高就可能卡了...
	if(apex.totalframes > 1) {
		totalsamples = apex.finalframeblocks + apex.blocksperframe * (apex.totalframes - 1);
	} else {
		totalsamples = apex.finalframeblocks;
	}
	// apectrl.totsec = totalsamples / apectrl.samplerate;		// 得到文件总时长
	// apectrl.bitrate = (fsize - apex.firstframe) * 8 / apectrl.totsec;	// 得到位速
	// apectrl.outsamples = APE_BLOCKS_PER_LOOP * 2;	// PCM输出数据量(16位为单位)
	// apectrl.datastart = apex.firstframe;	// 得到第一帧的地址
	totalsec = totalsamples / apex.samplerate;

	printf("  Samplerate: %d\r\n", apex.samplerate);
	printf("  Bits per sample: %d\r\n", apex.bps);
	printf("  First frame pos: %d\r\n", apex.firstframe);
	printf("  Duration: %02d:%02d \r\n", totalsec / 60, totalsec % 60);
	printf("  Bitrate: %d kbps\r\n", (fsize - apex.firstframe) * 8 / (totalsamples / apex.samplerate));

	printf("compressiontype : %d\r\n", apex.compressiontype);

	printf("totalframes : %d\r\n", apex.totalframes);
	printf("blocksperframe : %d\r\n", apex.blocksperframe);

	pAudio->sampleRate = apex.samplerate;
	pAudio->bitsPerSamplePerChannel = apex.bps;

	retSD = f_lseek(&SDFile, apex.firstframe);

	retSD = f_read(&SDFile, buffer, APE_FILE_BUF_SZ, (uint32_t *)&bytesinbuffer);
	if(retSD) {
		printf("file read error !\r\n");
		return -1;
	}

	firstbyte = 3;  		// Take account of the little-endian 32-bit byte ordering
	readptr = buffer;

	memset(pAudio->buff_A, 0x00, APE_BLOCKS_PER_LOOP * 4);
	memset(pAudio->buff_B, 0x00, APE_BLOCKS_PER_LOOP * 4);

	pAudio->play_buff = pAudio->buff_A;
	pAudio->read_buff = pAudio->buff_B;

	// -----
	// disp = 0;
	
	new_frame = 1;

	printf("\r\nfill buffer_A ...\r\n");
	process_ape_buffer();
	printf("\r\nfill buffer_B ...\r\n");
	process_ape_buffer();

	pAudio->bytesRead = APE_BLOCKS_PER_LOOP * 4;
	pAudio->play_size = (uint32_t)pAudio->bytesRead;

	printf("\r\nPlay_Size = %d\r\n", pAudio->play_size);
	audio_Start();

	return 0;

	// frame 循环
	while(currentframe < apex.totalframes) {	// 还有未解码的帧?
		// 计算一帧里面有多少个blocks?
		if(currentframe == (apex.totalframes - 1)) {
			nblocks = apex.finalframeblocks;
		} else  {
			nblocks = apex.blocksperframe;
		}
		apex.currentframeblocks = nblocks;

		// 初始化帧解码
		init_frame_decoder(&apex, readptr, &firstbyte, &bytesconsumed);

		readptr += bytesconsumed;

		bytesinbuffer -= bytesconsumed;

		// block 循环
		while(nblocks > 0) {
			blockstodecode = AUDIO_MIN(APE_BLOCKS_PER_LOOP, nblocks); // 获得一次要解码的blocks个数

			retSD = decode_chunk(&apex, readptr, &firstbyte, &bytesconsumed, decoded0, decoded1, blockstodecode);
			if(retSD != 0) {
				printf("block decode err\r\n");
				return -5;
			} else {
				printf("ape_decode_chunk  block : %d frame : %d\r\n", nblocks, currentframe);
			}

			ape_fill_buffer((uint16_t *)decoded1, APE_BLOCKS_PER_LOOP * 2);

			// delay_ms(100);

			readptr += bytesconsumed;			// 解码指针偏移到新数据位置
			bytesinbuffer -= bytesconsumed; 	// buffer里面的数据量减少

			if(bytesconsumed > 4 * APE_BLOCKS_PER_LOOP) {	//	出现错误了
				nblocks = 0;
				printf("bytesconsumed:%d\r\n", bytesconsumed);
				return -3;
			}

			if(bytesinbuffer < 4 * APE_BLOCKS_PER_LOOP) {	// 需要补充新数据了
				memmove(buffer, readptr, bytesinbuffer);
				retSD = f_read(&SDFile, buffer + bytesinbuffer, APE_FILE_BUF_SZ - bytesinbuffer, (uint32_t *)&n);
				if(retSD) {
					printf("file read error !\r\n");
					return -1;
				}
				bytesinbuffer += n;
				readptr = buffer;
			}
			nblocks -= blockstodecode;	// block计数递减

		}
		currentframe++;
	}
	printf("\r\nplay finished  %02d:%02d\r\n", min, sec);

	f_close(&SDFile);

	return 0;
}
























